using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Office = Microsoft.Office.Core;
using Excel = Microsoft.Office.Interop.Excel;
using System.Xml;
using System.Collections;
using System.IO.Packaging;

namespace LogAnalyzerIIS.LogClasses
{
	public class NSCALogConverter : LogConverter
	{
		protected override XmlDocument CreateWorksheetXML(List<string> sharedStringsOutput, string inputFilePath)
		{
			// for searching, the string is what we search for so it is the key
			// the int is the index which gets returned from a search
			Dictionary<string, int> sharedStringsSearch = new Dictionary<string, int>();

			XmlElement sheetData = PrepareWorksheetXML(sharedStringsOutput, sharedStringsSearch);

			// reading input file
			StreamReader inputFileReader = new StreamReader(inputFilePath);

			int[] columnMappings = new int[0];

			// Excel starts rows at index 1
			// (Row 1 is the column headers)
			int currentExcelRowIndex = 2;

			columnMappings = CreateColumnMappings();

			while (!inputFileReader.EndOfStream)
			{
				string inputLine = inputFileReader.ReadLine().Trim();

				// check that the line has text
				if (inputLine.Length > 0)
				{
					{
						// step 1, split the line up into its 10 component fields
						string[] inputLineValues = new string[10];

						// extract date and time
						int timeStartIndex = inputLine.IndexOf('[');
						int timeEndIndex = inputLine.IndexOf(']', timeStartIndex);

						// extract user IP, auth name and user name
						string userString = inputLine.Substring(0, timeStartIndex - 1).Trim();
						string[] userStrings = userString.Split(new char[] { ' ' });

						inputLineValues[0] = userStrings[0];
						inputLineValues[1] = userStrings[1];
						inputLineValues[2] = userStrings[2];

						string logTimeString = inputLine.Substring(timeStartIndex, timeEndIndex - timeStartIndex + 1).Trim();

						int colonIndex;
						if ((colonIndex = logTimeString.IndexOf(":")) > 0)
						{
							inputLineValues[3] = logTimeString.Substring(1, colonIndex - 1);
							inputLineValues[4] = logTimeString.Substring(colonIndex + 1, 8);
						}

						// extract method, uri stem and protocol version
						int methodStartIndex = inputLine.IndexOf('"', timeEndIndex);
						int methodEndIndex = inputLine.IndexOf('"', methodStartIndex + 1);
						string methodString = inputLine.Substring(methodStartIndex + 1, methodEndIndex - methodStartIndex - 1).Trim();
						string[] methodStrings = methodString.Split(new char[] { ' ' });

						inputLineValues[5] = methodStrings[0];
						inputLineValues[6] = methodStrings[1];
						inputLineValues[6] = methodStrings[2];

						// extract service status code and win32 status code
						string serviceString = inputLine.Substring(methodEndIndex + 1).Trim();
						string[] serviceStrings = serviceString.Split(new char[] { ' ' });

						inputLineValues[8] = serviceStrings[0];
						inputLineValues[9] = serviceStrings[1];
						inputLineValues[10] = serviceStrings[2];

						// step 2, add the to the output array using the order specified in the column mappings
						// (the output array is the same size and order of the output columns)
						string[] outputValues = new string[outputColumns.Count];
						for (int i = 0; i < outputColumns.Count; i++)
						{
							if (columnMappings[i] > -1)
								outputValues[i] = inputLineValues[columnMappings[i]];
							else
								outputValues[i] = "";
						}

						// write the row
						WriteRow(sheetData, currentExcelRowIndex, outputValues, sharedStringsSearch, sharedStringsOutput);

						// move on the next row
						currentExcelRowIndex++;
					}
				}
			}

			inputFileReader.Close();

			sharedStringsSearch.Clear();

			return worksheetXML;
		}

		/// <summary>
		///   Create column mappings by the W3C Extended log header row
		/// </summary>
		/// <param name="inputLine">
		///   Header row
		/// </param>
		private int[] CreateColumnMappings()
		{
			// initialize the column mapping array
			int[] outputColumnMappings = new int[outputColumns.Count];
			for (int i = 0; i < outputColumns.Count; i++)
				outputColumnMappings[i] = -1;

			outputColumnMappings[0] = 3;    // date
			outputColumnMappings[1] = 4;    // time
			outputColumnMappings[2] = 0;    // client IP
			outputColumnMappings[3] = 1;    // user name
			outputColumnMappings[8] = 5;    // method
			outputColumnMappings[9] = 6;    // uri stem
			outputColumnMappings[11] = 8;   // protocol status
			outputColumnMappings[16] = 7;   // protocol version
			outputColumnMappings[21] = 9;   // bytes transmitted
			outputColumnMappings[22] = 2;   // auth name

			return outputColumnMappings;
		}
	}
}
